package com.xushuda.yas.storage;

import java.util.NavigableMap;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * in fact is just a simple wrapper for T (NavigableMap<String, String>) used to index data in the memory
 * 
 * @author xushuda
 *
 */
public abstract class MemSlice implements IdxStorage {
    private Logger logger = Logger.getLogger(MemSlice.class.getName());

    // 单位byte

    // 在内存中缓存大小
    int bufSize;
    // block大小
    int blockSize; // TODO 暂时没有什么用，但是以后可以用来配合配置dump的策略

    public static final int DEFAULT_BUF_SIZE = 1 << 25; // 32M
    public static final int DEFAULT_BLOCK_SIZE = 1 << 17; // 128k
    // 存储数据的载体
    // 在子类中必须使用初始化块来初始化，或者传入了map并且不需要复制，否则抛出NullPointerException
    // 子类实现的时候需要传入comparator
    protected NavigableMap<String, SeqData> map;

    // 总字节数字
    protected volatile long totalBytes = 0L;

    // weather this object is a immutable memory table
    // immutable table 本身不能从外界修改，但是在compact过程中可能被改变
    protected boolean isImmutable;

    /**
     * 生成默认的MemSlcie
     */
    public MemSlice() {
        this(false);
    }

    /**
     * 默认了bufSize和blockSize
     * 
     * @param isImmutable
     */
    public MemSlice(boolean isImmutable) {
        this(isImmutable, DEFAULT_BUF_SIZE, DEFAULT_BLOCK_SIZE);
    }

    /**
     * 由传入的map初始化一个实例,不拷贝
     * 
     * @param isImmutable
     * @param map
     */
    public MemSlice(boolean isImmutable, NavigableMap<String, SeqData> map) {
        this(map, false, isImmutable, DEFAULT_BUF_SIZE, DEFAULT_BLOCK_SIZE);
    }

    /**
     * 默认用concurrentSkipList实现索引，空table
     * 
     * @param isImmutable
     * @param bufSize
     * @param blockSize
     */
    public MemSlice(boolean isImmutable, int bufSize, int blockSize) {
        this(new ConcurrentSkipListMap<String, SeqData>(), false, isImmutable, bufSize, blockSize);
    }

    /**
     * 配置所有参数
     * 
     * @param map
     * @param copy 是否拷贝传入的map
     * @param isImmutable
     * @param bufSize
     * @param blockSize
     * @throws NullPointerException
     */
    public MemSlice(NavigableMap<String, SeqData> map, boolean copy, boolean isImmutable, int bufSize, int blockSize) {
        // 强制copy,如果在初始化块中没有初始化map，则会抛出NullPointer异常
        if (copy) {
            this.map.putAll(map);
        } else {
            this.map = map;
        }
        this.isImmutable = isImmutable;
        this.bufSize = bufSize;
        this.blockSize = blockSize;
    }

    /**
     * insert data into the memSlice
     * 
     * @param key
     * @param data
     * @throws RuntimeException
     */
    @Override
    public void insert(String key, String value, long seqNo) {
        if (!isImmutable) {
            // totalBytes += value.getBytes().length;
            // 采用近似值

            SeqData vd = new SeqData();
            vd.value = value;
            vd.born = seqNo;
            // null 意味着插入成功
            map.put(key, vd);
            totalBytes += (value.length() + key.length()) * 1.1;
            if (totalBytes < 0) {
                logger.log(Level.SEVERE, "totalBytes overflow");
            }
        } else {
            throw new RuntimeException("illegal insertion on immutable memory table");
        }
    }

    /**
     * weather contains key contains 并不比get方法快
     * 
     * @param key
     * @return
     */
    @Override
    public boolean contains(String key, long currentSeqNo) {
        SeqData d = map.get(key);

        if (d != null && d.born < currentSeqNo && (d.tomb == 0 || d.tomb > currentSeqNo)) {
            return true;
        }
        return false;
    }

    /**
     * get the data indexed by the key 查询某key对应的值
     * 
     * @param key
     * @return 不存在返回null
     */
    @Override
    public String find(String key, long currentSeqNo) {
        SeqData d = map.get(key);

        if (d != null && d.born <= currentSeqNo && (d.tomb == 0 || d.tomb > currentSeqNo)) {
            return map.get(key).value;
        }

        return null;
    }

    public void update(String k, String v, long seqNo) {

    }

    public void remove(String k, long seqNo) {

    }

    public String[] findBetween(String key, long currentSeqNo) {
        return null;
    }

    /**
     * weather should flush data to the immutable slice 只有不是immutable的table才能flush dump的策略
     * 
     * @return
     */
    public boolean shouldFlush() {
        return !isImmutable && totalBytes >= bufSize;// TODO
    }

    /**
     * 获取索引范围内的map 注意：返回的内容可能会被修改 需要正确地处理sk和ek为null的情况
     * 
     * @param sk
     * @param ek
     * @return
     */
    public SortedMap<String, SeqData> range(String sk, String ek) {
        if (null == ek && null == sk) {
            return map;
        } else if (null == ek && null != sk) {
            return map.tailMap(sk, true);
        } else if (null == sk && null != ek) {
            return map.headMap(ek, true);
        } else {
            return map.subMap(sk, true, ek, true);
        }
    }

    // /**
    // * return the next high entry of the map
    // *
    // * @param key
    // * @return if the key == null return the least key of the whole map
    // */
    // public Entry<String, SeqData> nextH(String key) {
    // return null != key ? map.higherEntry(key) : least();
    // }

    // /**
    // * least entry
    // *
    // * @return
    // */
    // public Entry<String, SeqData> least() {
    // return map.firstEntry();
    // }

    /**
     * flush some of this map to a immutable memSlice immutable 的flushMap不应该被调用
     * 
     * @return 返回一个新的用跳跃链表实现的immutable MemSlice，包含getFlushMap中的数据内容(不会拷贝map中的内容)
     * @throws RuntimeException
     */
    public MemSlice flushMap() {
        if (isImmutable) {
            throw new RuntimeException("illegal flush on immutable map");
        } else {
            // totalBytes 归零
            totalBytes = 0L;

            // 默认的实现不会拷贝map的内容，所以不需要初始化map
            return new MemSlice(true, getFlushMap()) {
                // {
                // map = new ConcurrentSkipListMap<String, String>();
                // }

                @Override
                protected NavigableMap<String, SeqData> getFlushMap() {
                    return null;
                }

            };
        }
    }

    /**
     * 被子类实现，可以使用不同的策略来flush数据 ;被flush的部分数据不应该还再当前类的 table中存在
     * 
     * @return
     */
    protected abstract NavigableMap<String, SeqData> getFlushMap();

}
